home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / cvs / sprite / RCS / update.c,v < prev   
Encoding:
Text File  |  1991-09-11  |  14.8 KB  |  625 lines

  1. head     1.4;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.4
  10. date     91.09.10.23.14.23;  author jhh;  state Exp;
  11. branches ;
  12. next     1.3;
  13.  
  14. 1.3
  15. date     91.09.10.16.13.47;  author jhh;  state Exp;
  16. branches ;
  17. next     1.2;
  18.  
  19. 1.2
  20. date     91.09.10.16.12.36;  author jhh;  state Exp;
  21. branches ;
  22. next     1.1;
  23.  
  24. 1.1
  25. date     91.09.04.22.33.57;  author jhh;  state Exp;
  26. branches ;
  27. next     ;
  28.  
  29.  
  30. desc
  31. @@
  32.  
  33.  
  34. 1.4
  35. log
  36. @got rid of -e option
  37. @
  38. text
  39. @#ifndef lint
  40. static char rcsid[] = "$Id: update.c,v 1.2 91/09/10 16:12:36 jhh Exp Locker: jhh $";
  41. #endif !lint
  42.  
  43. /*
  44.  *    Copyright (c) 1989, Brian Berliner
  45.  *
  46.  *    You may distribute under the terms of the GNU General Public License
  47.  *    as specified in the README file that comes with the CVS 1.0 kit.
  48.  *
  49.  *    "update" updates the version in the present directory with respect to
  50.  *    the RCS repository.  The present version must have been created by
  51.  *    "checkout".  The user can keep up-to-date by calling "update" whenever
  52.  *    he feels like it.
  53.  *
  54.  *    The present version can be committed by "commit", but this keeps the
  55.  *    version in tact.
  56.  *
  57.  *    "update" accepts the following options:
  58.  *        -p    Prunes empty directories
  59.  *        -l    Local; does not do a recursive update
  60.  *        -q    Quiet; does not print a message when
  61.  *                recursively updating
  62.  *        -Q    Really quiet
  63.  *        -d    Directory; causes update to create new directories
  64.  *                as they are added to the RCS repository
  65.  *        -f    Forces a match for the -r revision
  66.  *        -r tag    Revision; only extract from revision "tag"
  67.  *        -D date    Updates to the revision specified by "date"
  68.  *
  69.  *    Arguments following the options are taken to be file names
  70.  *    to be updated, rather than updating the entire directory.
  71.  *
  72.  *    Modified or non-existent RCS files are checked out and reported
  73.  *    as U <user_file>
  74.  *
  75.  *    Modified user files are reported as M <user_file>.  If both the
  76.  *    RCS file and the user file have been modified, the user file
  77.  *    is replaced by the result of rcsmerge, and a backup file is
  78.  *    written for the user in .#file.version.  If this throws up
  79.  *    irreconcilable differences, the file is reported as C <user_file>,
  80.  *    and as M <user_file> otherwise.
  81.  *
  82.  *    Files added but not yet committed are reported as A <user_file>.
  83.  *    Files removed but not yet decommitted are reported as R <user_file>.
  84.  *
  85.  *    If the current directory contains subdirectories that hold
  86.  *    concurrent versions, these are updated too.  If the -d option
  87.  *    was specified, new directories added to the repository are
  88.  *    automatically created and updated as well.
  89.  */
  90.  
  91. #include <sys/param.h>
  92. #include <sys/types.h>
  93. #include <sys/stat.h>
  94. #include <dirent.h>
  95. #include "cvs.h"
  96.  
  97. char update_dir[MAXPATHLEN];
  98. int update_recursive = 1;
  99. int update_build_dirs = 0;
  100. int update_prune_dirs = 0;
  101.  
  102. static int really_recursive = 1;
  103.  
  104. update(argc, argv)
  105.     int argc;
  106.     char *argv[];
  107. {
  108.     FILE *fp;
  109.     int c, err = 0;
  110.  
  111.     if (argc == -1)
  112.     update_usage();
  113.     optind = 1;
  114.     while ((c = getopt(argc, argv, "pflQqdr:D:")) != -1) {
  115.     switch (c) {
  116.     case 'l':
  117.         really_recursive = 0;
  118.         update_recursive = 0;
  119.         break;
  120.     case 'Q':
  121.         really_quiet = 1;
  122.         /* FALL THROUGH */
  123.     case 'q':
  124.         quiet = 1;
  125.         break;
  126.     case 'd':
  127.         update_build_dirs = 1;
  128.         break;
  129.     case 'f':
  130.         force_tag_match = 1;
  131.         break;
  132.     case 'r':
  133.         (void) strcpy(Tag, optarg);
  134.         break;
  135.     case 'D':
  136.         Make_Date(optarg, Date);
  137.         break;
  138.     case 'p':
  139.         update_prune_dirs = 1;
  140.         break;
  141.     case '?':
  142.     default:
  143.         update_usage();
  144.         break;
  145.     }
  146.     }
  147.     argc -= optind;
  148.     argv += optind;
  149.     if (!isdir(CVSADM)) {
  150.     if (!quiet)
  151.         warn(0, "warning: no %s directory found", CVSADM);
  152.     if (argc <= 0) {
  153.         err += update_descend(update_recursive);
  154.     } else {
  155.         int i;
  156.  
  157.         for (i = 0; i < argc; i++) {
  158.         if (isdir(argv[i])) {
  159.             (void) strcat(Dlist, " ");
  160.             (void) strcat(Dlist, argv[i]);
  161.         } else {
  162.             warn(0, "nothing known about %s", argv[i]);
  163.             err++;
  164.         }
  165.         }
  166.         err += update_process_lists();
  167.     }
  168.     return (err);
  169.     }
  170.     Name_Repository();
  171.     Reader_Lock();
  172.     if (argc <= 0) {
  173.     /*
  174.      * When updating the entire directory, and recursively building
  175.      * directories, must make sure that the "static" file in the
  176.      * administration is removed before calling Find_Names().
  177.      */
  178.     if (update_build_dirs)
  179.         (void) unlink(CVSADM_ENTSTAT);
  180.     if (force_tag_match && (Tag[0] != '\0' || Date[0] != '\0'))
  181.         Find_Names(&fileargc, fileargv, ALLPLUSATTIC);
  182.     else
  183.         Find_Names(&fileargc, fileargv, ALL);
  184.     fp = open_file(CVSADM_MOD, "w+"); /* create a NULL Mod file */
  185.     (void) fclose(fp);
  186.     argc = fileargc;
  187.     argv = fileargv;
  188.     } else {
  189.     /*
  190.      * Not recursive if files were specified on the command line
  191.      */
  192.     update_recursive = 0;
  193.     }
  194.     if (Collect_Sets(argc, argv) != 0)
  195.     error(0, "failed; correct the above errors first");
  196.     free_names(&fileargc, fileargv);
  197.     err += update_process_lists();
  198.     /*
  199.      * XXX - Might be nice to sort the Mod file here, removing unique
  200.      * entries as we go, but it's currently not necessary, as "diff"
  201.      * is the only one that uses it, and he does the sort "as needed".
  202.      */
  203.     Lock_Cleanup(0);
  204.     /*
  205.      * Make directories, and descend them if requested to.
  206.      */
  207.     err += update_make_dirs(update_build_dirs && update_recursive);
  208.     err += update_descend(update_recursive);
  209.     Lock_Cleanup(0);
  210.     return (err);
  211. }
  212.  
  213. /*
  214.  * Process the lists created by Collect_Sets().
  215.  */
  216. static
  217. update_process_lists()
  218. {
  219.     char backup[MAXPATHLEN], dlist[MAXLISTLEN];
  220.     FILE *fp;
  221.     char *cp;
  222.     int update_Files = 0, err = 0;
  223.  
  224.     /*
  225.      * Wlist is the "remove entry" list.
  226.      */
  227.     for (cp = strtok(Wlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  228.     update_Files = 1;
  229.     (void) strcpy(User, cp);
  230.     Scratch_Entry(User);
  231.     if (!really_quiet) {
  232.         if (update_dir[0])
  233.         printf("D %s/%s\n", update_dir, User);
  234.         else
  235.         printf("D %s\n", User);
  236.     }
  237.     (void) unlink(User);
  238.     }
  239.     /*
  240.      * Olist is the "needs checking out" list.
  241.      */
  242.     for (cp = strtok(Olist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  243.     update_Files = 1;
  244.     (void) strcpy(User, cp);
  245.     Locate_RCS();
  246.     (void) sprintf(backup, "%s/%s%s", CVSADM, CVSPREFIX, User);
  247.     if (isreadable(User))
  248.         rename_file(User, backup);
  249.     else
  250.         (void) unlink(backup);
  251.     if (Tag[0] != '\0' || Date[0] != '\0') {
  252.         Version_Number(Rcs, Tag, Date, VN_Rcs);
  253.         (void) sprintf(prog, "%s/%s -q -r%s %s %s", Rcsbin, RCS_CO,
  254.                VN_Rcs, Rcs, User);
  255.     } else {
  256.         (void) sprintf(prog, "%s/%s -q %s %s", Rcsbin, RCS_CO, Rcs, User);
  257.     }
  258.     if (system(prog) == 0) {
  259.         if (cvswrite == TRUE)
  260.         xchmod(User, 1);
  261.         Version_TS(Rcs, Tag, User);
  262.         Register(User, VN_Rcs, TS_User);
  263.         if (!really_quiet) {
  264.         if (update_dir[0])
  265.             printf("U %s/%s\n", update_dir, User);
  266.         else
  267.             printf("U %s\n", User);
  268.         }
  269.     } else {
  270.         if (isreadable(backup))
  271.         rename_file(backup, User);
  272.         warn(0, "could not check out %s", User);
  273.         err++;
  274.     }
  275.     (void) unlink(backup);
  276.     }
  277.     /*
  278.      * Mlist is the "modified, needs checking in" list.
  279.      */
  280.     for (cp = strtok(Mlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  281.     update_Files = 1;
  282.     (void) strcpy(User, cp);
  283.     if (!really_quiet) {
  284.         if (update_dir[0])
  285.         printf("M %s/%s\n", update_dir, User);
  286.         else
  287.         printf("M %s\n", User);
  288.     }
  289.     fp = open_file(CVSADM_MOD, "a");
  290.     if (fprintf(fp, "%s\n", User) == EOF)
  291.         error(1, "cannot write %s", CVSADM_MOD);
  292.     (void) fclose(fp);
  293.     }
  294.     /*
  295.      * Alist is the "to be added" list.
  296.      */
  297.     for (cp = strtok(Alist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  298.     update_Files = 1;
  299.     (void) strcpy(User, cp);
  300.     if (!really_quiet) {
  301.         if (update_dir[0])
  302.         printf("A %s/%s\n", update_dir, User);
  303.         else
  304.         printf("A %s\n", User);
  305.     }
  306.     }
  307.     /*
  308.      * Rlist is the "to be removed" list.
  309.      */
  310.     for (cp = strtok(Rlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  311.     update_Files = 1;
  312.     (void) strcpy(User, cp);
  313.     if (!really_quiet) {
  314.         if (update_dir[0])
  315.         printf("R %s/%s\n", update_dir, User);
  316.         else
  317.         printf("R %s\n", User);
  318.     }
  319.     }
  320.     /*
  321.      * Glist is the "modified, needs merging" list.
  322.      *
  323.      * The users currently modified file is moved to a backup file
  324.      * name ".#filename.version", so that it will stay around for about
  325.      * three days before being automatically removed by some cron
  326.      * daemon.  The "version" is the version of the file that the
  327.      * user was most up-to-date with before the merge.
  328.      */
  329.     for (cp = strtok(Glist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  330.     update_Files = 1;
  331.     (void) strcpy(User, cp);
  332.     Locate_RCS();
  333.     Version_TS(Rcs, Tag, User);
  334.     (void) sprintf(backup, "%s%s.%s", BAKPREFIX, User, VN_User);
  335.     (void) unlink(backup);
  336.     copy_file(User, backup);
  337.     xchmod(User, 1);
  338.     (void) sprintf(prog, "%s/%s -r%s %s", Rcsbin, RCS_MERGE,
  339.                VN_User, Rcs);
  340.     if (system(prog) != 0) {
  341.         warn(0, "could not merge revision %s of %s",
  342.          VN_User, User);
  343.         warn(0, "backup file for %s is in %s", User, backup);
  344.         err++;
  345.         continue;
  346.     }
  347.     Register(User, VN_Rcs, TS_Rcs);
  348.     (void) sprintf(prog, "%s -s '%s' %s", GREP, RCS_MERGE_PAT, User);
  349.     if (system(prog) == 0) {
  350.         warn(0, "conflicts found in %s", User);
  351.         if (!really_quiet) {
  352.         if (update_dir[0])
  353.             printf("C %s/%s\n", update_dir, User);
  354.         else
  355.             printf("C %s\n", User);
  356.         }
  357.     } else {
  358.         if (!really_quiet) {
  359.         if (update_dir[0])
  360.             printf("M %s/%s\n", update_dir, User);
  361.         else
  362.             printf("M %s\n", User);
  363.         }
  364.     }
  365.     fp = open_file(CVSADM_MOD, "a");
  366.     if (fprintf(fp, "%s\n", User) == EOF)
  367.         error(1, "cannot write %s", CVSADM_MOD);
  368.     (void) fclose(fp);
  369.     }
  370.     if (Dlist[0]) {
  371.     int save_recursive = update_recursive;
  372.  
  373.     update_recursive = really_recursive;
  374.     Lock_Cleanup(0);        /* cleanup locks before descending */
  375.     (void) strcpy(dlist, Dlist);    /* to get it on the stack... */
  376.     for (cp = strtok(dlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  377.         err += update_descend_dir(cp);
  378.     }
  379.     update_recursive = save_recursive;
  380.     }
  381.     if (update_Files != 0)
  382.     Entries2Files();
  383.     return (err);
  384. }
  385.  
  386. /*
  387.  * When automatically creating directories from the repository in the
  388.  * local work directory, we scan for directories that don't exist locally
  389.  * and create them with a NULL administration directory for now, which
  390.  * is filled by update later.
  391.  */
  392. static
  393. update_make_dirs(doit)
  394.     int doit;
  395. {
  396.     char fname[MAXPATHLEN], tmp[MAXPATHLEN];
  397.     DIR *dirp;
  398.     struct dirent *dp;
  399.     int err = 0;
  400.  
  401.     if (doit) {
  402.     if ((dirp = opendir(Repository)) == NULL) {
  403.         warn(0, "cannot open directory %s", Repository);
  404.         err++;
  405.     } else while ((dp = readdir(dirp)) != NULL) {
  406.         if (strcmp(dp->d_name, ".") == 0 ||
  407.         strcmp(dp->d_name, "..") == 0 ||
  408.         strcmp(dp->d_name, CVSATTIC) == 0 ||
  409.         strcmp(dp->d_name, CVSLCK) == 0)
  410.         continue;
  411.         (void) sprintf(fname, "%s/%s", Repository, dp->d_name);
  412.         (void) sprintf(tmp, "%s/%s", dp->d_name, CVSADM);
  413.         if (!isdir(fname))
  414.         continue;
  415.         if (islink(dp->d_name) || isdir(tmp))
  416.         continue;
  417.         if (!isdir(dp->d_name) && isfile(dp->d_name)) {
  418.         warn(0, "file %s should be a directory; please move it", dp->d_name);
  419.         err++;
  420.         } else {
  421.         make_directory(dp->d_name);
  422.         if (chdir(dp->d_name) < 0) {
  423.             warn(0, "cannot chdir to %s", dp->d_name);
  424.             err++;
  425.         } else {
  426.             (void) strcpy(tmp, Repository);
  427.             (void) strcpy(Repository, fname);
  428.             Create_Admin(Repository, DFLT_RECORD);
  429.             (void) chdir("..");
  430.             (void) strcpy(Repository, tmp);
  431.         }
  432.         }
  433.     }
  434.     if (dirp)
  435.         (void) closedir(dirp);
  436.     }
  437.     return (err);
  438. }
  439.  
  440. /*
  441.  * If doalldirs is set, does a recursive update by calling update_descend_dir()
  442.  * for each file in the current directory.
  443.  */
  444. static
  445. update_descend(doalldirs)
  446.     int doalldirs;
  447. {
  448.     DIR *dirp;
  449.     struct dirent *dp;
  450.     int err = 0;
  451.  
  452.     if (doalldirs) {
  453.     if ((dirp = opendir(".")) == NULL) {
  454.         err++;
  455.     } else {
  456.         while ((dp = readdir(dirp)) != NULL) {
  457.         if (strcmp(dp->d_name, ".") == 0 ||
  458.             strcmp(dp->d_name, "..") == 0)
  459.             continue;
  460.         err += update_descend_dir(dp->d_name);
  461.         }
  462.         (void) closedir(dirp);
  463.     }
  464.     }
  465.     return (err);
  466. }
  467.  
  468. /*
  469.  * This is the recursive function that walks the argument directory looking
  470.  * for sub-directories that have CVS administration files in them
  471.  * and updates them recursively.
  472.  *
  473.  * Note that we do not follow symbolic links here, which is a feature!
  474.  */
  475. static
  476. update_descend_dir(dir)
  477.     char *dir;
  478. {
  479.     char cwd[MAXPATHLEN], fname[MAXPATHLEN];
  480.     char *cp;
  481.     int err;
  482.  
  483.     (void) sprintf(fname, "%s/%s", dir, CVSADM);
  484.     if (!isdir(dir) || islink(dir) || !isdir(fname))
  485.     return (0);
  486.     if (getwd(cwd) == NULL) {
  487.     warn(0, "cannot get working directory: %s", cwd);
  488.     return (1);
  489.     }
  490.     if (update_dir[0] == '\0')
  491.     (void) strcpy(update_dir, dir);
  492.     else {
  493.     (void) strcat(update_dir, "/");
  494.     (void) strcat(update_dir, dir);
  495.     }
  496.     if (!quiet)
  497.     printf("%s %s: Updating %s\n", progname, command, update_dir);
  498.     if (chdir(dir) < 0) {
  499.     warn(1, "cannot chdir to %s", update_dir);
  500.     err = 1;
  501.     goto out;
  502.     }
  503.     err = update(0, (char **)0);
  504.     if ((cp = rindex(update_dir, '/')) != NULL)
  505.     *cp = '\0';
  506.     else
  507.     update_dir[0] = '\0';
  508. out:
  509.     if (chdir(cwd) < 0)
  510.     error(1, "cannot chdir to %s", cwd);
  511.     if (update_prune_dirs && isemptydir(dir)) {
  512.     (void) sprintf(prog, "%s -fr %s", RM, dir);
  513.     (void) system(prog);
  514.     }
  515.     return (err);
  516. }
  517.  
  518. /*
  519.  * Returns 1 if the argument directory is completely empty, other than
  520.  * the existence of the CVS.adm directory entry.  Zero otherwise.
  521.  */
  522. isemptydir(dir)
  523.     char *dir;
  524. {
  525.     DIR *dirp;
  526.     struct dirent *dp;
  527.  
  528.     if ((dirp = opendir(dir)) == NULL) {
  529.         warn(0, "cannot open directory %s for empty check", dir);
  530.     return (0);
  531.     }
  532.     while ((dp = readdir(dirp)) != NULL) {
  533.         if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 &&
  534.             strcmp(dp->d_name, CVSADM) != 0) {
  535.             (void) closedir(dirp);
  536.             return (0);
  537.         }
  538.     }
  539.     (void) closedir(dirp);
  540.     return (1);
  541. }
  542.  
  543. static
  544. update_usage()
  545. {
  546.     (void) fprintf(stderr,
  547.            "Usage: %s %s [-Qqlfp] [-d] [-r tag|-D date] [files...]\n",
  548.            progname, command);
  549.     exit(1);
  550. }
  551. @
  552.  
  553.  
  554. 1.3
  555. log
  556. @removed debugging printfs
  557. @
  558. text
  559. @a63 1
  560. char *no_prune[MAXFILEPERDIR] = {NULL};
  561. a71 1
  562.     char **keep = no_prune;
  563. d76 1
  564. a76 1
  565.     while ((c = getopt(argc, argv, "pflQqdr:D:e:")) != -1) {
  566. a102 4
  567.     case 'e':
  568.         *keep++ = optarg;
  569.         *keep = NULL;
  570.         break;
  571. a443 2
  572.     char **keep;
  573.     int found;
  574. a472 1
  575.     found = 0;
  576. d474 2
  577. a475 10
  578.     for(keep = no_prune; *keep != NULL; keep++) {
  579.         if (!strcmp(dir, *keep)) {
  580.         found = 1;
  581.         break;
  582.         }
  583.     }
  584.     if (!found) {
  585.         (void) sprintf(prog, "%s -fr %s", RM, dir);
  586.         (void) system(prog);
  587.     }
  588. @
  589.  
  590.  
  591. 1.2
  592. log
  593. @added -e option to allow exceptions to pruning
  594. @
  595. text
  596. @d2 1
  597. a2 1
  598. static char rcsid[] = "$Id: update.c,v 1.27.1.2 91/02/06 18:30:07 berliner Exp $";
  599. a482 1
  600.     printf("update_descend_dir: %s\n", dir);
  601. a483 1
  602.         printf("\t%s\n", *keep);
  603. @
  604.  
  605.  
  606. 1.1
  607. log
  608. @Initial revision
  609. @
  610. text
  611. @d64 1
  612. d73 1
  613. d78 1
  614. a78 1
  615.     while ((c = getopt(argc, argv, "pflQqdr:D:")) != -1) {
  616. d105 4
  617. d199 6
  618. d450 2
  619. d481 1
  620. d483 12
  621. a494 2
  622.     (void) sprintf(prog, "%s -fr %s", RM, dir);
  623.     (void) system(prog);
  624. @
  625.